package com.suredy.app.porject.ctrl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.suredy.app.porject.constants.ContractStatus;
import com.suredy.app.porject.constants.ContractType;
import com.suredy.app.porject.constants.FlowStatus;
import com.suredy.app.porject.ctrl.view.ViewRoleCtrl;
import com.suredy.app.porject.model.Bid;
import com.suredy.app.porject.model.BidMoney;
import com.suredy.app.porject.model.Contract;
import com.suredy.app.porject.model.ContractPayinPlan;
import com.suredy.app.porject.model.ContractPayoutPlan;
import com.suredy.app.porject.model.ContractWorkPlan;
import com.suredy.app.porject.service.BidMoneySrv;
import com.suredy.app.porject.service.BidSrv;
import com.suredy.app.porject.service.ContractPayinPlanSrv;
import com.suredy.app.porject.service.ContractPayoutPlanSrv;
import com.suredy.app.porject.service.ContractSrv;
import com.suredy.app.porject.service.ContractWorkPlanSrv;
import com.suredy.app.porject.service.FlowOfBid2UserSrv;
import com.suredy.app.porject.service.FlowOfContract2UserSrv;
import com.suredy.core.ctrl.BaseCtrl;

/**
 * 首页，我的应用控制器
 * 
 * @author VIVID.G
 * @since 2015-10-12
 * @version v0.1
 */
@Controller
@RequestMapping("/front-page")
public class FrontPageCtrl extends BaseCtrl {

	/* 七天以内 */
	private final int ALARM_DATE_SIZE = 7;

	@Autowired
	private BidSrv bidSrv;

	@Autowired
	private ContractSrv contractSrv;

	@Autowired
	private FlowOfBid2UserSrv bid2UserSrv;

	@Autowired
	private FlowOfContract2UserSrv contract2UserSrv;

	@Autowired
	private ContractPayinPlanSrv contractPayinPlanSrv;

	@Autowired
	private ContractPayoutPlanSrv contractPayoutPlanSrv;

	@Autowired
	private ContractWorkPlanSrv contractWorkPlanSrv;

	@Autowired
	private BidMoneySrv bidMoneySrv;

	@RequestMapping(method = RequestMethod.GET)
	public String index(Model model) {
		String view = "app/front-page/index";

		ViewRoleCtrl vc = new ViewRoleCtrl(this.getRoles(), this.getUser());

		model.addAttribute("roles", vc);

		// 招标专责
		if (vc.isBidZhuanze())
			model.addAttribute("toBid", this.myTodoBid());

		// 合同专责
		if (vc.isContractZhuanze())
			model.addAttribute("toContract", this.myBidForContract());

		// 项目专责
		if (vc.isXiangmuHeader())
			model.addAttribute("workPlan", this.myWorkPlan());

		// 收款专责
		if (vc.isMoneyIn())
			model.addAttribute("payinPlan", this.myPayinPlan());

		// 付款专责
		if (vc.isMoneyOut())
			model.addAttribute("payoutPlan", this.myPayoutPlan());

		// 待履行合同
		if (vc.isStartContract())
			model.addAttribute("contractForStart", this.contractForStart());

		// 待回收投标保证金
		if (vc.isBidZhuanze())
			model.addAttribute("backTbbzj", this.getBackTbbzj());

		return view;
	}

	@RequestMapping(value = "/bid-total", method = RequestMethod.POST)
	@ResponseBody
	public Object getBidTotal(Integer year) {
		Map<String, Long> data = null;

		if (year == null)
			data = this.bidSrv.getBidStatusTotal(null, null);
		else
			data = this.bidSrv.getBidStatusTotal(this.getYearStart(year), this.getYearEnd(year));

		Map<String, Object> ret = new HashMap<String, Object>();

		ret.put("xData", data.keySet());
		ret.put("yData", data.values());

		return ret;
	}

	@RequestMapping(value = "/contract-total", method = RequestMethod.POST)
	@ResponseBody
	public Object getContractTotal(Integer year) {
		Map<String, Long> data;
		if (year == null)
			data = this.contractSrv.getContractTotal(null, null, ContractType.MAIN_CONTRACT_TYPES);
		else
			data = this.contractSrv.getContractTotal(this.getYearStart(year), this.getYearEnd(year), ContractType.MAIN_CONTRACT_TYPES);

		Map<String, Object> ret = new HashMap<String, Object>();

		ret.put("xData", data.keySet());
		ret.put("yData", data.values());

		return ret;
	}

	@RequestMapping(value = "/contract-satus-total", method = RequestMethod.POST)
	@ResponseBody
	public Object getContractStatusTotal(Integer year) {
		Map<String, Long> data;
		if (year == null)
			data = this.contractSrv.getContractStatusTotal(null, null, ContractType.MAIN_CONTRACT_TYPES);
		else
			data = this.contractSrv.getContractStatusTotal(this.getYearStart(year), this.getYearEnd(year), ContractType.MAIN_CONTRACT_TYPES);

		Map<String, Object> ret = new HashMap<String, Object>();

		ret.put("xData", data.keySet());
		ret.put("yData", data.values());

		return ret;
	}

	@RequestMapping(value = "/ht-money-total", method = RequestMethod.POST)
	@ResponseBody
	public Object getHtMoneyTotal(Integer year) {
		DetachedCriteria dc = this.contractSrv.getDc(null);

		// 只统计收款合同（两个收款主合同）
		dc.add(Restrictions.in("type", new ContractType[] {ContractType.MAIN, ContractType.B_CONTRACT}));

		if (year != null) {
			Criterion start = Restrictions.and(Restrictions.ge("start", this.getYearStart(year)), Restrictions.le("start", this.getYearEnd(year)));
			Criterion end = Restrictions.and(Restrictions.ge("end", this.getYearStart(year)), Restrictions.le("end", this.getYearEnd(year)));

			dc.add(Restrictions.or(start, end));
		}

		List<String> xData = new ArrayList<String>();
		xData.add("合同金额");
		xData.add("结算金额");
		xData.add("已收金额");
		xData.add("未收金额");

		int page = 1;
		List<Double> yData = new ArrayList<Double>(4);
		yData.add(0d);
		yData.add(0d);
		yData.add(0d);
		yData.add(0d);

		while (true) {
			List<Contract> data = this.contract2UserSrv.getContractOf(dc, null, null, page++, 30, FlowStatus.FS2001_CONTRACT_CREATED, FlowStatus.FS2002_CONTRACT_STARTED, FlowStatus.FS2003_CONTRACT_COMPLETED);

			if (data == null || data.isEmpty())
				break;

			for (Contract c : data) {
				// 合同金额
				yData.set(0, (yData.get(0) + (c.getPrice() == null ? 0 : c.getPrice())));
				// 结算金额
				yData.set(1, (yData.get(1) + (c.getClearingPrice() == null ? 0 : c.getClearingPrice())));
				// 已收金额
				yData.set(2, (yData.get(2) + (c.getSkje() == null ? 0 : c.getSkje())));
				// 未收金额
				yData.set(3, (yData.get(3) + (c.getWsje() == null ? 0 : c.getWsje())));
			}
		}

		Map<String, Object> ret = new HashMap<String, Object>();
		ret.put("xData", xData);
		ret.put("yData", yData);

		return ret;
	}

	/**
	 * 经营资金情况
	 * 
	 * @return
	 */
	@RequestMapping(value = "/jy-money-total", method = RequestMethod.POST)
	@ResponseBody
	public Object getJyMoneyTotal(Integer year) {
		DetachedCriteria dc = this.contractSrv.getDc(null);

		// 只统计收款合同（两个收款主合同）
		dc.add(Restrictions.in("type", ContractType.MAIN_CONTRACT_TYPES));

		if (year != null) {
			Criterion start = Restrictions.and(Restrictions.ge("start", this.getYearStart(year)), Restrictions.le("start", this.getYearEnd(year)));
			Criterion end = Restrictions.and(Restrictions.ge("end", this.getYearStart(year)), Restrictions.le("end", this.getYearEnd(year)));

			dc.add(Restrictions.or(start, end));
		}

		List<String> xData = new ArrayList<String>();
		xData.add("总支金额");
		xData.add("已支金额");
		xData.add("未支金额");
		xData.add("利润金额");

		int page = 1;
		List<Double> yData = new ArrayList<Double>(4);
		yData.add(0d);
		yData.add(0d);
		yData.add(0d);
		yData.add(0d);

		while (true) {
			List<Contract> data = this.contract2UserSrv.getContractOf(dc, null, null, page++, 30, FlowStatus.FS2001_CONTRACT_CREATED, FlowStatus.FS2002_CONTRACT_STARTED, FlowStatus.FS2003_CONTRACT_COMPLETED);

			if (data == null || data.isEmpty())
				break;

			for (Contract c : data) {
				// 总支金额
				yData.set(0, (yData.get(0) + (c.getZcje() == null ? 0 : c.getZcje())));
				// 已支金额
				yData.set(1, (yData.get(1) + (c.getFkje() == null ? 0 : c.getFkje())));
				// 未支金额
				yData.set(2, (yData.get(2) + (c.getWfje() == null ? 0 : c.getWfje())));
				// 利润金额
				yData.set(3, (yData.get(3) + (c.getLr() == null ? 0 : c.getLr())));
			}
		}

		Map<String, Object> ret = new HashMap<String, Object>();
		ret.put("xData", xData);
		ret.put("yData", yData);

		return ret;
	}

	/**
	 * 合同金额占比
	 * 
	 * @return
	 */
	@RequestMapping(value = "/zb-money-total", method = RequestMethod.POST)
	@ResponseBody
	public Object getContractMoneyZb(Integer year) {
		String ql = "SELECT T.companyA, SUM(T.price) FROM Contract T WHERE T.type IN (:TYPE) AND T.flowStatus IN (:FLOW) {year} GROUP BY T.companyA ORDER BY SUM(T.price) DESC";

		List<Object> params = new ArrayList<Object>();

		Object[] types = ContractType.IN_MONEY_CONTRACT_TYPE.toArray();
		String type = "";
		for (Object o : types) {
			if (!StringUtils.isBlank(type))
				type += ",";
			type += "?";
			params.add(o);
		}
		ql = ql.replace(":TYPE", type);

		Object[] flows = new FlowStatus[] {FlowStatus.FS2001_CONTRACT_CREATED, FlowStatus.FS2002_CONTRACT_STARTED, FlowStatus.FS2003_CONTRACT_COMPLETED};
		String flow = "";
		for (Object o : flows) {
			if (!StringUtils.isBlank(flow))
				flow += ",";
			flow += "?";
			params.add(o);
		}
		ql = ql.replace(":FLOW", flow);

		if (year != null) {
			String start = "(T.start >= ? and T.start <= ?)";
			String end = "(T.end >= ? and T.end <= ?)";

			ql = ql.replace("{year}", " AND (" + start + " OR " + end + ") ");

			params.add(this.getYearStart(year));
			params.add(this.getYearEnd(year));
			params.add(this.getYearStart(year));
			params.add(this.getYearEnd(year));
		} else
			ql = ql.replace("{year}", "");

		int page = 1;
		Map<String, Object> ret = new HashMap<String, Object>();
		List<String> xData = new ArrayList<String>();
		List<Double> yData = new ArrayList<Double>();
		ret.put("xData", xData);
		ret.put("yData", yData);

		// 获取top10
		while (true) {
			@SuppressWarnings("unchecked")
			List<Object[]> data = (List<Object[]>) this.contractSrv.readByQL(ql, page++, 30, params.toArray());

			if (data == null || data.isEmpty())
				break;

			for (int i = 0; i < data.size(); i++) {
				Object[] d = data.get(i);

				if (d == null || d.length != 2)
					continue;

				String company = (String) d[0];
				Double count = (Double) d[1];

				if (StringUtils.isBlank(company))
					continue;

				if (count == null)
					count = 0d;

				if (i == 10) // 第11个使用合计
					xData.add("其他合计");
				else if (i < 10) // 前10个直接保存合同名称
					xData.add(company);

				if (i == 11) {
					yData.set(10, yData.get(10) + count); // 从第12个开始都叠加到第11个元素上
				} else
					yData.add(count); // 前11个直接保存值
			}
		}

		return ret;
	}

	@RequestMapping(value = "/ht-company-a-total", method = RequestMethod.POST)
	@ResponseBody
	public Object getHtCompanyATotal(Integer year) {
		String ql = "SELECT T.companyA, COUNT(T) FROM Contract T WHERE T.type IN (:TYPE) AND T.flowStatus IN (:FLOW) {year} GROUP BY T.companyA ORDER BY COUNT(T) DESC, T.companyA";

		List<Object> params = new ArrayList<Object>();

		Object[] types = ContractType.IN_MONEY_CONTRACT_TYPE.toArray();
		String type = "";
		for (Object o : types) {
			if (!StringUtils.isBlank(type))
				type += ",";
			type += "?";
			params.add(o);
		}
		ql = ql.replace(":TYPE", type);

		Object[] flows = new FlowStatus[] {FlowStatus.FS2001_CONTRACT_CREATED, FlowStatus.FS2002_CONTRACT_STARTED, FlowStatus.FS2003_CONTRACT_COMPLETED};
		String flow = "";
		for (Object o : flows) {
			if (!StringUtils.isBlank(flow))
				flow += ",";
			flow += "?";
			params.add(o);
		}
		ql = ql.replace(":FLOW", flow);

		if (year != null) {
			String start = "(T.start >= ? and T.start <= ?)";
			String end = "(T.end >= ? and T.end <= ?)";

			ql = ql.replace("{year}", " AND (" + start + " OR " + end + ") ");

			params.add(this.getYearStart(year));
			params.add(this.getYearEnd(year));
			params.add(this.getYearStart(year));
			params.add(this.getYearEnd(year));
		} else
			ql = ql.replace("{year}", "");

		int page = 1;
		Map<String, Object> ret = new HashMap<String, Object>();
		List<String> xData = new ArrayList<String>();
		List<Long> yData = new ArrayList<Long>();
		ret.put("xData", xData);
		ret.put("yData", yData);

		// 获取top10
		while (true) {
			@SuppressWarnings("unchecked")
			List<Object[]> data = (List<Object[]>) this.contractSrv.readByQL(ql, page++, 30, params.toArray());

			if (data == null || data.isEmpty())
				break;

			for (Object[] os : data) {
				String s = (String) os[0];
				long i = (long) os[1];

				if (StringUtils.isBlank(s))
					continue;

				if (i == 10) // 第11个使用合计
					xData.add("其他合计");
				else if (i < 10) // 前10个直接保存合同名称
					xData.add(s);

				if (i == 11) {
					yData.set(10, yData.get(10) + i); // 从第12个开始都叠加到第11个元素上
				} else
					yData.add(i); // 前11个直接保存值
			}
		}

		return ret;
	}

	private List<Bid> myTodoBid() {
		String[] userIds = new String[] {this.getUser().getId()};

		List<Bid> data = this.bid2UserSrv.getAllBidOf(null, userIds, true, FlowStatus.FS1000_BID_CREATED);

		return data == null || data.isEmpty() ? null : data;
	}

	private List<Bid> myBidForContract() {
		String[] userIds = new String[] {this.getUser().getId()};

		List<Bid> data = this.bid2UserSrv.getAllBidOf(null, userIds, true, FlowStatus.FS1001_BID_CONTRACT_CREATED);

		return data == null || data.isEmpty() ? null : data;
	}

	private List<ContractWorkPlan> myWorkPlan() {
		List<ContractWorkPlan> data = this.contractWorkPlanSrv.getAlarmPlanList(this.getUser().getId(), this.get7DaysAfterNow());

		return data == null || data.isEmpty() ? null : data;
	}

	private List<ContractPayinPlan> myPayinPlan() {
		List<ContractPayinPlan> data = this.contractPayinPlanSrv.getAlarmPlanList(this.getUser().getId(), this.get7DaysAfterNow());

		return data == null || data.isEmpty() ? null : data;
	}

	private List<ContractPayoutPlan> myPayoutPlan() {
		List<ContractPayoutPlan> data = this.contractPayoutPlanSrv.getAlarmPlanList(this.getUser().getId(), this.get7DaysAfterNow());

		return data == null || data.isEmpty() ? null : data;
	}

	private List<Contract> contractForStart() {
		Contract search = new Contract();
		search.setStatus(ContractStatus.WAIT);
		search.setFlowStatus(FlowStatus.FS2001_CONTRACT_CREATED);

		List<Contract> data = this.contractSrv.readByEntity(search);

		return data == null || data.isEmpty() ? null : data;
	}

	private List<BidMoney> getBackTbbzj() {
		List<BidMoney> data = this.bidMoneySrv.getNeedBackMoney(null, this.get7DaysAfterNow(), this.getUser().getId());

		return data == null || data.isEmpty() ? null : data;
	}

	private Date get7DaysAfterNow() {
		Calendar c = Calendar.getInstance();

		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);

		c.add(Calendar.DATE, this.ALARM_DATE_SIZE + 1);

		return c.getTime();
	}

	private Date getYearStart(int year) {
		Calendar c = Calendar.getInstance();

		c.set(Calendar.YEAR, year);
		c.set(Calendar.MONTH, Calendar.JANUARY); // 1月
		c.set(Calendar.DAY_OF_MONTH, 1); // 1日
		c.set(Calendar.HOUR_OF_DAY, 0); // 0时
		c.set(Calendar.MINUTE, 0); // 0分
		c.set(Calendar.SECOND, 0); // 0秒
		c.set(Calendar.MILLISECOND, 0); // 0毫秒

		return c.getTime();
	}

	private Date getYearEnd(int year) {
		Calendar c = Calendar.getInstance();

		c.set(Calendar.YEAR, year + 1);
		c.set(Calendar.MONTH, Calendar.JANUARY); // 1月
		c.set(Calendar.DAY_OF_MONTH, 1); // 1日
		c.set(Calendar.HOUR_OF_DAY, 0); // 0时
		c.set(Calendar.MINUTE, 0); // 0分
		c.set(Calendar.SECOND, 0); // 0秒
		c.set(Calendar.MILLISECOND, 0); // 0毫秒

		c.add(Calendar.MILLISECOND, -1);

		return c.getTime();
	}

}
